# https://www.liaoxuefeng.com/wiki/1016959663602400/1017317609699776

# 模式匹配 相当于js的switch...case...
import functools


# def get_score(score):
#     match score:
#         case 1:
#             print('score is 1')
#         case _:
#             print('score is {}'.format(score))
# get_score(2)


# 循环
'''
for i in []
for i in range(10)
while ... break/continue
'''

# dict和set
# a = {'name':'zs','age':10}
# b = {1, 2, 'ls'}
# b1 = set([3, 5, 'ww'])
# print(a)
# print(b)
# print(b1)

# 函数
# def fn1(name, age=15, address='cn', **kw):
#   print('{} is {} years old, living in {}, others={}'.format(name, age, address, kw))
# fn1('zs', age=20, dog='wangcai', cat="cafe")

# 高级特性
# 切片
# a = [1, 2, 3, 4, 5]
# str = 'abcdef'
# print(a[0])
# print(a[-1])
# print(a[1:])
# print(a[0:3])
# print(a[:3])
# print(a[:])
# print(str[:3])
# print(str[::2])

# 迭代
# a = {'name':'zs','age':10}
# for key in a:
#   print('{}: {}'.format(key, a[key]))
# for ch in 'abc':
#   print(ch)
# for i,value in enumerate(['A', 'B', 'C']):
#   print(i,value)
# for x,y in [(1,1),(2,3)]:
#   print(x,y)

# 列表生成式
# a = list(range(1,10))
# print(a)
# b = list(x*x for x in range(1,11))
# print(b)
# c = list(x*x for x in range(1,11) if x % 2 == 0)
# print(c)
# d = list(m+n for m in 'ABC' for n in 'XYZ')
# print(d)
# person = {'name':'zs','age':10}
# e = list('{}={}'.format(k,v) for k,v in person.items())
# print(person.items(),e)
# f = list(x*x if x % 2 == 0 else 'odd' for x in range(1,11))
# print(f)

# 生成器generator
# 创建generator
# g = (x*x for x in range(10))
# for i in g:
#   print(i)
# 斐波拉契数列
# F(0) = 0, F(1) = 1
# F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
# def fib(max):
#   n, a, b = 0, 0, 1
#   while n < max:
#     print(b)
#     a, b = b, a + b
#     n = n + 1
#   return 'done'
# fib(2)

# def fib(max):
#   n, a, b = 0, 0, 1
#   while n < max:
#     yield b
#     a, b = b, a + b
#     n = n + 1
#   return 'done'
# g = fib(6)
# for n in g:
#   print(n)
# while True:
#   try:
#     x = next(g)
#     print('g:', x)
#   except StopIteration as e:
#     print('Generator return value:', e.value)
#     break
# 杨辉三角

# 迭代器


# 函数式编程
# 高阶函数
# map/reduce
# def f(x):
#   return x*x
# r = map(f, [1, 2, 3])
# print(list(r))
# r1 = map(str, [1, 2, 3])
# print(list(r1))
# from functools import reduce
# def f(x, y):
#   return x + y
# sum = reduce(f, [1, 2, 3])
# print(sum)

# filter过滤
# def f(x):
#   return x % 2 == 0
# fil1 = list(filter(f, list(range(10))))
# print(fil1)

# sorted排序
# s1 = sorted([5, 3, 4, 2, 1, -4], key=abs) #key接收一个函数
# print(s1)

# 闭包 函数返回函数

# 匿名函数
# l1 = list(map(lambda x: x*x, list(range(1,11))))
# print(l1)
# def build(x, y):
#   return lambda: x * x + y * y
# print(build(1, 2)())

# 装饰器
# def log(func):
#     def wrapper(*args, **kw):
#         print('call %s():' % func.__name__)
#         return func(*args, **kw)
#     return wrapper
# @log
# def now():
#     print('2024-5')
# now()

# def log(text):
#     def decorator(func):
#         @functools.wraps(func)
#         def wrapper(*args, **kw):
#             print('%s %s():' % (text, func.__name__))
#             return func(*args, **kw)
#         return wrapper
#     return decorator

# @log('title')
# def now():
#     print('2024-5')
# now()

# 偏函数 functools.partial
# int2 = functools.partial(int, base=2)
# print(int2('10010'))

# max2 = functools.partial(max, 11)
# print(max2(5, 10, 2))


# 面向对象编程
# 类和实例
# class Student():

#     def __init__(self, name, score):
#         self.name = name
#         self.score = score
    
#     def print_score(self):
#         print('{}\'s score is {}'.format(self.name, self.score))

#     def get_grade(self):
#         if self.score >= 90:
#             return 'A'
#         elif self.score >= 60:
#             return 'B'
#         else:
#             return 'C'

# zs = Student('zhangsan', 90)
# zs.print_score()
# print(zs.get_grade())

# 访问限制
# class Student():

#     def __init__(self, name, score):
#         # __私有变量，外部无法访问
#         self.__name = name
#         self.__score = score
    
#     # 外部获取私有变量的方法
#     def get_name(self):
#         return self.__name
    
#     def get_score(self):
#         return self.__score
    
#     # 外部设置私有变量的方法
#     def set_score(self, score):
#         if 0 <= score <= 100:
#             self.__score = score
#         else:
#             raise ValueError('bad score')

# zs = Student('zhangsan', 90)
# print(zs.__name) # => err
# print(zs.get_name())
# zs.set_score(101)
# print(zs.get_score())


# 继承和多态
# class Animal():
#     def run(self):
#         print('Animal is running...')

# class Dog(Animal):
#     def run(self):
#         print('Dog is running...')


# class Tortoise(Animal):
#     def run(self):
#         print('Tortoise is running slowly...')

# dog1 = Dog()
# # dog1.run()
# # 判断一个变量是否是某个类型可以用isinstance()判断
# # print(isinstance(dog1, Animal))
# def run_twice(animal):
#     animal.run()
#     animal.run()

# run_twice(Tortoise())


# 获取对象信息
# print(type(123))
# print(dir('ABC'))

# 实例属性和类属性
# class Student():
#     name = 'student'

# s = Student()
# print(s.name)
# s.name = 'Mike'
# print(s.name)
# print(Student.name)


# 面向对象高级编程
# 使用__slots__动态给class添加功能
# class Student(object):
#     __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

# s = Student()
# s.name = 'zs'
# s.age = 10
# s.score = 90 # => err

# @property装饰器就是负责把一个方法变成属性调用的：
# 只定义getter方法，不定义setter方法就是一个只读属性
# class Student(object):

#     @property
#     def score(self):
#         return self._score

#     @score.setter
#     def score(self, value):
#         if not isinstance(value, int):
#             raise ValueError('score must be an integer!')
#         if value < 0 or value > 100:
#             raise ValueError('score must between 0 ~ 100!')
#         self._score = value

# s = Student()
# s.score = 999


# 多重继承
# class Animal(object):
#     pass

# # 大类:
# class Mammal(Animal):
#     pass

# # 功能
# class Runnable(object):
#     def run(self):
#         print('Running...')

# class Dog(Mammal, Runnable):
#     pass


# 定制类
# __repr__打印看到内部数据
# class Student(object):
#     def __init__(self, name):
#         self.name = name
#     def __str__(self):
#         return 'Student object (name=%s)' % self.name
#     __repr__ = __str__

# s = Student('zs')
# print(s)

# __iter__实现类被用于for ... in循环
# class Fib(object):
#     def __init__(self):
#         self.a, self.b = 0, 1 # 初始化两个计数器a，b

#     def __iter__(self):
#         return self # 实例本身就是迭代对象，故返回自己

#     def __next__(self):
#         self.a, self.b = self.b, self.a + self.b # 计算下一个值
#         if self.a > 100000: # 退出循环的条件
#             raise StopIteration()
#         return self.a # 返回下一个值

# for n in Fib():
#     print(n)


# __getitem__表现得像list那样按照下标取出元素
# class Fib(object):
#     def __getitem__(self, n):
#         if isinstance(n, int): # n是索引
#             a, b = 1, 1
#             for x in range(n):
#                 a, b = b, a + b
#             return a
#         if isinstance(n, slice): # n是切片
#             start = n.start
#             stop = n.stop
#             if start is None:
#                 start = 0
#             a, b = 1, 1
#             L = []
#             for x in range(stop):
#                 if x >= start:
#                     L.append(a)
#                 a, b = b, a + b
#             return L
        
# f = Fib()
# print(f[0:10])


# __getattr__当调用不存在的属性时，返回一个??而不是报错
# class Student(object):

#     def __init__(self):
#         self.name = 'Michael'

#     def __getattr__(self, attr):
#         if attr=='score':
#             return 99
        
# s = Student()
# print(s.score)

# 定义一个__call__()方法，就可以直接对实例进行调用
# class Student(object):
#     def __init__(self, name):
#         self.name = name

#     def __call__(self):
#         print('My name is %s.' % self.name)

# s = Student('Michael')
# # s()
# # callable判断是否能被调用
# print(callable(s))


# 使用枚举类
from enum import Enum, unique
# Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
# for name, member in Month.__members__.items():
#     print(name, '=>', member, ',', member.value)

# @unique装饰器可以帮助我们检查保证没有重复值。
# @unique
# class Weekday(Enum):
#     Sun = 0 # Sun的value被设定为0
#     Mon = 1
#     Tue = 2
#     Wed = 3
#     Thu = 4
#     Fri = 5
#     Sat = 6

# print(Weekday(7))
# for name, member in Weekday.__members__.items():
#     print(name, '=>', member)